using LoggingMagic.AssemlyOperations;
using LoggingMagic.LoggingParameters;
using LoggingMagic.Tests.Consts;
using NUnit.Framework;
using System.Linq;
using Rhino.Mocks;

namespace LoggingMagic.Tests.AssemblyOperations
{
    [TestFixture]
    internal class MethodFinderTests
    {
        private MethodFinder _target;

        [SetUp]
        public void Setup()
        {
            Setup(false);
        }

        private void Setup(bool logGetters)
        {
            var accessor = new AssemblyAccessor();
            var assemblyInfo = accessor.ParseAssembly(Const.MainDll, null);

            var module = assemblyInfo.AssemblyDefinition.MainModule;
            //var methodFinderParameters = MockRepository.GenerateStub<IMethodFinderParameters>();
            var methodFinderParameters = new MethodFinderParameters(null) { LogGetters = logGetters };
            _target = new MethodFinder(module, new AttributesFinder(assemblyInfo.AssemblyResolver, module), methodFinderParameters);
        }

        #region base class with attribute with no parameters
        [Test]
        public void LogAtributeIsInheritedFromBaseClass()
        {
            var result = _target.FindMethods();
            var method = result.Where(x => x.MethodDefinition.FullName.EndsWith("ChildClass::Test()")).Single();

            //default value
            Assert.AreEqual(1, method.Attribute.ConstructorArguments.Count);
            Assert.AreEqual(false, method.Attribute.ConstructorArguments[0].Value);
        }

        [Test]
        public void LogAttributeWithDirectParameter1()
        {
            var result = _target.FindMethods();
            var method = result.Where(x => x.MethodDefinition.FullName.EndsWith("ChildClass::TestWithParams()")).Single();

            Assert.AreEqual(1, method.Attribute.ConstructorArguments.Count);
            Assert.AreEqual(true, method.Attribute.ConstructorArguments[0].Value);
        }

        [Test]
        public void LogAttributeWithDirectParameter2()
        {
            var result = _target.FindMethods();
            var method = result.Where(x => x.MethodDefinition.FullName.EndsWith("ChildClass::TestWithoutParams()")).Single();

            Assert.AreEqual(1, method.Attribute.ConstructorArguments.Count);
            Assert.AreEqual(false, method.Attribute.ConstructorArguments[0].Value);
        }
        #endregion


        #region base class with attribute with parameters
        [Test]
        public void ParameterizeBase_LogAtributeIsInheritedFromBaseClass()
        {
            var result = _target.FindMethods();
            var method = result.Where(x => x.MethodDefinition.FullName.EndsWith("ChildClassFromParameterized::Test()")).Single();

            Assert.AreEqual(1, method.Attribute.ConstructorArguments.Count);
            Assert.AreEqual(true, method.Attribute.ConstructorArguments[0].Value);
        }

        [Test]
        public void ParameterizeBase_LogAttributeWithDirectParameter1()
        {
            var result = _target.FindMethods();
            var method = result.Where(x => x.MethodDefinition.FullName.EndsWith("ChildClassFromParameterized::TestWithAttr()")).Single();

            //default value
            Assert.AreEqual(1, method.Attribute.ConstructorArguments.Count);
            Assert.AreEqual(false, method.Attribute.ConstructorArguments[0].Value);
        }

        [Test]
        public void ParameterizeBase_LogAttributeWithDirectParameter2()
        {
            var result = _target.FindMethods();
            var method = result.Where(x => x.MethodDefinition.FullName.EndsWith("ChildClassFromParameterized::TestWithAttrFalse()")).Single();

            Assert.AreEqual(1, method.Attribute.ConstructorArguments.Count);
            Assert.AreEqual(false, method.Attribute.ConstructorArguments[0].Value);
        }

        [Test]
        public void ParameterizeBase_LogAttributeWithDirectParameter3()
        {
            var result = _target.FindMethods();
            var method = result.Where(x => x.MethodDefinition.FullName.EndsWith("ChildClassFromParameterized::TestWithAttrTrue()")).Single();

            Assert.AreEqual(1, method.Attribute.ConstructorArguments.Count);
            Assert.AreEqual(true, method.Attribute.ConstructorArguments[0].Value);
        }
        #endregion


        [Test]
        public void SetPropertyWithAttributeSet()
        {
            var result = _target.FindMethods();
            var method = result.Where(x => x.MethodDefinition.FullName.EndsWith("ChildClass::set_TestProperty(System.Int32)")).Single();

            Assert.AreEqual(1, method.Attribute.ConstructorArguments.Count);
            Assert.AreEqual(true, method.Attribute.ConstructorArguments[0].Value);
        }

        [Test]
        public void GetPropertyWithAttributeSet()
        {
            Setup(true);

            var result = _target.FindMethods();
            var method = result.Where(x => x.MethodDefinition.FullName.EndsWith("ChildClass::get_TestProperty()")).Single();

            Assert.AreEqual(1, method.Attribute.ConstructorArguments.Count);
            Assert.AreEqual(true, method.Attribute.ConstructorArguments[0].Value);
        }

        [Test]
        public void GetPropertyWithAttributeSet_GetNotLogged()
        {
            var result = _target.FindMethods();
            Assert.IsFalse(result.Any(x => x.MethodDefinition.FullName.EndsWith("ChildClass::get_TestProperty()")));
        }

        [Test]
        public void PropertyWithNoLogAttribute()
        {
            var result = _target.FindMethods();
            Assert.IsFalse(result.Any(x => x.MethodDefinition.FullName.EndsWith("ChildClass::set_TestProperty2(System.Int32)")));
            Assert.IsFalse(result.Any(x => x.MethodDefinition.FullName.EndsWith("ChildClass::get_TestProperty2(System.Int32)")));
        }

        [Test]
        public void TestClassWithGlobalAttribute_CtorExists()
        {
            var result = _target.FindMethods();
            var method = result.Where(x => x.MethodDefinition.FullName.Contains("TestClassWithGlobalAttribute")).Single();

            Assert.AreEqual(1, method.Attribute.ConstructorArguments.Count);
            Assert.AreEqual(true, method.Attribute.ConstructorArguments[0].Value);
        }


        [Test]
        public void AbstractFunctions_NotFound()
        {
            var result = _target.FindMethods();
            Assert.IsFalse(result.Any(x => x.MethodDefinition.FullName.Contains("BaseClass::AbstractFunction()")));
        }

        [Test]
        public void AbstractProperty_NotFound()
        {
            Setup(true);

            var result = _target.FindMethods();
            Assert.IsFalse(result.Any(x => x.MethodDefinition.FullName.Contains("BaseClass::get_AbstractProperty()")));
            Assert.IsFalse(result.Any(x => x.MethodDefinition.FullName.Contains("BaseClass::set_AbstractProperty(System.Int32)")));
        }




    }
}